package de.fuberlin.inf.alp4.uebg5;

import java.util.concurrent.BlockingQueue;
import java.util.concurrent.LinkedBlockingQueue;

public class Scheduler {

	@SuppressWarnings("unchecked")
	private BlockingQueue<MessageRequest> queue;
	@SuppressWarnings("unchecked")
	private BlockingQueue<MessageRequest> waitingQueue;
    final Servant servant;

	@SuppressWarnings("unchecked")
	public Scheduler() {
    	System.out.println("Scheduler initialized");
        this.queue = new LinkedBlockingQueue<MessageRequest>();
        this.waitingQueue = new LinkedBlockingQueue<MessageRequest>();
        this.servant = new Servant();
        new Thread(new Runnable() { public void run() { dispatch(); } }).start();
	}

    @SuppressWarnings("unchecked")
	protected void dispatch() {
    	System.out.println("Entering Scheduler Loop");
    	for (;;) {
		    MessageRequest r;
		    //first check for free elements in the waiting queue
		    //because there always are elements with the higher priority
		    //
		    //waiting queue will always be checked when there a MessageRequest
		    //exists which is unblocked and changes the m1 Servant
		    //so it might be possible that the guard would return true now
		    for(int i = 0; i < this.waitingQueue.size(); i++) {
		    	try {
		    		r = waitingQueue.take();
		    		System.out.println("Took MessageRequest (" + r.priority + ") from " +
		    				"waitingQueue (" + r.getRequestType() + ")");
		    		if(r.guard()) {
		    			System.out.println("MessageRequest NOT guarded. Executing..");
		    			r.run();
		    			break;
		    		} else {
		    			System.out.println("MessageRequest guarded. " +
    					"Putting back to the waiting queue (" + r.getRequestType() + ")");
		    			waitingQueue.put(r);
		    		}
		    	} catch (InterruptedException e) {
			    	System.err.println("Error taking MessageRequest");
		    	}
		    }
		    
		    //the loop working on our queue
		    for (;;) {
		    	try {
		    		if(this.queue.size() == 0)
		    			break;
		    		int maxPrio = this.getMaxPrio();	
		    		r = this.getHighestRequest(maxPrio);
		    		System.out.println("Took MessageRequest (" + r.priority + ") from queue" +
		    				" (" + r.getRequestType() + ")");
		    		if(r.guard()) {
		    			System.out.println("MessageRequest NOT guarded");
		    			r.run();
		    			break;
		    		}
		    		else {
		    			System.out.println("MessageRequest guarded. " +
		    					"Putting back to the waiting queue (" + r.getRequestType() + ")");
		    			waitingQueue.put(r);
		    		}		    			
		    	} catch (InterruptedException e) {
			    	System.err.println("Error taking MessageRequest");
		    	}
		    }
		}
    }
    
    @SuppressWarnings("unchecked")
	private int getMaxPrio() throws InterruptedException {
    	int max = 0;
    	MessageRequest request;
    	for(int i = 0; i < this.queue.size(); i++) {
    		request = this.queue.take();
    		if(request.priority > max)
    			max = request.priority;
    		this.queue.put(request);
    	}
    	return max;
    }
    
    @SuppressWarnings("unchecked")
	private MessageRequest getHighestRequest(int max) throws InterruptedException {
    	MessageRequest request;
    	for(int i = 0; i < this.queue.size(); i++) {
    		request = this.queue.take();
    		if(request.priority == max)
    			return request;
    		else
    			this.queue.put(request);
    	} 
    	return this.queue.take();
    }

    @SuppressWarnings("unchecked")
	public void enqueue(MessageRequest r) {
		for (;;) {
		    try {
		    	queue.put(r);
		    	System.out.println("Added MessageRequest to queue");
		    	break;
		    } catch (InterruptedException e) {
				System.err.println("Could not add MessageRequest");
		    }
	    }
	}
}
